/*
 * Copyright (c) 2009. Silenus Consultoria, S.L.
 */
package es.silenus.detecta.controller;

import es.silenus.detecta.Constants;

import es.silenus.detecta.dao.*;

import es.silenus.detecta.model.*;

import es.silenus.detecta.util.FreemarkerHelper;
import es.silenus.detecta.util.MailHelper;

import org.apache.commons.lang.StringUtils;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.ServletRequestUtils;

import java.sql.Timestamp;

import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


/**
 * Survey answer controller, loads and saves filled surveys and no role is required to execute its methods.
 *
 * @author <a href="mailto:malonso@silenus-consultoria.es">Mariano Alonso</a>
 *
 * @since 02-jun-2009 11:59:14
 */
public class SurveyAnswerController extends BaseController {
	/**
	 * Logger for this class.
	 */
	private static final Log LOG = LogFactory.getLog(SurveyAnswerController.class);


	/**
	 * The organization DAO.
	 */
	private OrganizationDAO organizationDAO;

	/**
	 * The survey DAO.
	 */
	private SurveyDAO surveyDAO;

	/**
	 * The survey Unit Answer Dao.
	 */
	private SurveyAnswerHeaderDAO surveyAnswerHeaderDAO;

	/**
	 * The council dao.
	 */
	private CouncilDAO councilDAO;

	/**
	 * The training dao.
	 */
	private TrainingActionDAO trainingDAO;

	/**
	 * The user DAO.
	 */
	private UserDAO userDAO;

	/**
	 * The remember subject key.
	 */
	private String mailSubjectKey;

	/**
	 * The alternate text key.
	 */
	private String alternateKey;

	/**
	 * The encoding.
	 */
	private String encoding;

	/**
	 * The base URL.
	 */
	private String baseURL;

	/**
	 * The new answer template.
	 */
	private String newAnswerTemplate;

	/**
	 * The confirmation template.
	 */
	private String confirmationTemplate;

	/**
	 * The mail helper.
	 */
	private MailHelper mailHelper;

	/**
	 * The freemarker helper.
	 */
	private FreemarkerHelper freemarkerHelper;

	/**
	 * Gets the survey answer header dao.
	 *
	 * @return the survey answer header dao
	 */
	public SurveyAnswerHeaderDAO getSurveyAnswerHeaderDAO() {
		return surveyAnswerHeaderDAO;
	}

	/**
	 * Sets the organization DAO.
	 *
	 * @param organizationDAO the organization DAO.
	 */
	public void setOrganizationDAO(final OrganizationDAO organizationDAO) {
		this.organizationDAO = organizationDAO;
	}

	/**
	 * Sets the survey answer header dao.
	 *
	 * @param surveyAnswerHeaderDAO the new survey answer header dao
	 */
	public void setSurveyAnswerHeaderDAO(SurveyAnswerHeaderDAO surveyAnswerHeaderDAO) {
		this.surveyAnswerHeaderDAO = surveyAnswerHeaderDAO;
	}

	/**
	 * Sets the survey DAO.
	 *
	 * @param surveyDAO the survey DAO.
	 */
	public void setSurveyDAO(final SurveyDAO surveyDAO) {
		this.surveyDAO = surveyDAO;
	}

	/**
	 * Sets the council dao.
	 *
	 * @param councilDAO the new council dao
	 */
	public void setCouncilDAO(CouncilDAO councilDAO) {
		this.councilDAO = councilDAO;
	}

	/**
	 * Sets the training dao.
	 *
	 * @param trainingDAO the new training dao
	 */
	public void setTrainingDAO(TrainingActionDAO trainingDAO) {
		this.trainingDAO = trainingDAO;
	}

	/**
	 * Sets the user DAO.
	 *
	 * @param userDAO the user DAO.
	 */
	public void setUserDAO(final UserDAO userDAO) {
		this.userDAO = userDAO;
	}

	/**
	 * Sets the remember subject key.
	 *
	 * @param mailSubjectKey the remember subject key.
	 */
	public void setMailSubjectKey(final String mailSubjectKey) {
		this.mailSubjectKey = mailSubjectKey;
	}

	/**
	 * Sets the alternate key.
	 *
	 * @param alternateKey the alternate key.
	 */
	public void setAlternateKey(final String alternateKey) {
		this.alternateKey = alternateKey;
	}

	/**
	 * Sets the encoding.
	 *
	 * @param encoding the encoding.
	 */
	public void setEncoding(final String encoding) {
		this.encoding = encoding;
	}

	/**
	 * Sets the base URL.
	 *
	 * @param baseURL the base URL.
	 */
	public void setBaseURL(final String baseURL) {
		this.baseURL = baseURL;
	}

	/**
	 * Sets the new answer template.
	 *
	 * @param newAnswerTemplate the new answer template.
	 */
	public void setNewAnswerTemplate(final String newAnswerTemplate) {
		this.newAnswerTemplate = newAnswerTemplate;
	}

	/**
	 * Sets the confirmation template.
	 *
	 * @param confirmationTemplate the confirmation template.
	 */
	public void setConfirmationTemplate(final String confirmationTemplate) {
		this.confirmationTemplate = confirmationTemplate;
	}

	/**
	 * Sets the mail helper.
	 *
	 * @param mailHelper the mail helper.
	 */
	public void setMailHelper(final MailHelper mailHelper) {
		this.mailHelper = mailHelper;
	}

	/**
	 * Sets the freemarker helper.
	 *
	 * @param freemarkerHelper the freemarker helper.
	 */
	public void setFreemarkerHelper(final FreemarkerHelper freemarkerHelper) {
		this.freemarkerHelper = freemarkerHelper;
	}

	/**
	 * Load survey.
	 *
	 * @param request the request
	 * @param response the response
	 *
	 * @return the string
	 */
	public String loadSurvey(final HttpServletRequest request, final HttpServletResponse response) {
		String surveyId = request.getParameter("id");

		if(StringUtils.isEmpty(surveyId)) {
			return "survey-not-found";
		} else {
			int id = Integer.parseInt(surveyId);

			Survey survey = surveyDAO.findById(id);

			if(survey == null) {
				return "survey-not-found";
			}

			// Check for survey expiration
			Timestamp now = new Timestamp(System.currentTimeMillis());

			if((survey.getLifecycle().getId() > SurveyLifecycle.PRODUCTION.getId()) || now.after(survey.getEndDate())) {
				return "survey-closed";
			}

			List<Map<String, Object>> result = surveyDAO.fetchQuestionTree(survey.getId());

			request.setAttribute("survey", survey);
			request.setAttribute("questions", result);
		}

		return "survey";
	}

	/**
	 * Save survey.
	 *
	 * @param request the request
	 * @param response the response
	 *
	 * @return the string
	 *
	 * @throws ServletRequestBindingException the servlet request binding exception
	 */
	public String saveSurvey(final HttpServletRequest request, final HttpServletResponse response)
			throws ServletRequestBindingException {
		String result = "survey-saved";
		String id = request.getParameter("survey");
		Survey survey = null;

		if(!StringUtils.isEmpty(id)) {
			survey = surveyDAO.findById(Integer.parseInt(id));
		}

		if(survey != null) {
			SurveyAnswerHeader header = new SurveyAnswerHeader();
			String entityId = ServletRequestUtils.getRequiredStringParameter(request, "DNI");

			if(!surveyAnswerHeaderDAO.hasEntity(survey.getId(), entityId)) {
				// Header
				header.setSurvey(survey);

				String councilId = ServletRequestUtils.getRequiredStringParameter(request, "council");

				String trainingActionId = ServletRequestUtils.getRequiredStringParameter(request, "training");
				Integer internetConnection = ServletRequestUtils.getRequiredBooleanParameter(request, "internetConnection") ? 0
						: 1;

				header.setAction(trainingDAO.findById(Integer.valueOf(trainingActionId)));
				header.setCouncil(councilDAO.findById(councilId));

				header.setEntityId(entityId);
				header.setInternetConnection(internetConnection);

				// Unit answers
				String value;
				SurveyUnitAnswer answer;
				TrainingPreference preference;

				for(Question q : survey.getQuestions()) {
					value = request.getParameter(String.valueOf(q.getId()));

					if(!StringUtils.isEmpty(value)) {
						answer = new SurveyUnitAnswer();
						answer.setHeader(header);
						answer.setQuestion(q);

						preference = TrainingPreference.getById(Integer.parseInt(value));

						answer.setPreference(preference);
						header.add(answer);
					}
				}

				surveyAnswerHeaderDAO.save(header);

				// Put survey into production state
				if(survey.getLifecycle() == SurveyLifecycle.DESIGN) {
					survey.setLifecycle(SurveyLifecycle.PRODUCTION);
					surveyDAO.save(survey);
				}


				// Build model
				Map<String, Object> model = new HashMap<String, Object>();

				String fullname = request.getParameter("firstName") + " " + request.getParameter("lastName");
				String email = request.getParameter("email");
				Locale locale = request.getLocale();

				model.put("fullname", fullname);
				model.put("email", email);
				model.put("entityId", entityId);
				model.put("locale", locale);
				model.put("survey", survey);
				model.put("header", header);
				model.put("baseURL", baseURL);


				// Send administrator notification
				List<User> admins = userDAO.getAdministrators(survey.getOrganization().getId());

				if((admins != null) && (admins.size() > 0)) {
					User admin = admins.get(0);

					sendNewAnswerEmail(admin, model);
				}

				// Send confirmation email
				sendConfirmationEmail(fullname, email, locale, model);
			} else {
				request.setAttribute(Constants.ERRORS, "survey.entity.duplicated");
				result = "survey-error";
			}
		}

		return result;
	}

	private boolean sendConfirmationEmail(
			final String fullname, final String email, final Locale locale, final Map<String, Object> model) {
		try {
			String message = freemarkerHelper.process(confirmationTemplate, locale, encoding, model);

			mailHelper.sendHTML(email, fullname, locale, mailSubjectKey, alternateKey, message);

			return true;
		} catch(Exception e) {
			LOG.error("Error sending mail to worker: " + email, e);

			return false;
		}
	}

	private boolean sendNewAnswerEmail(final User user, final Map<String, Object> model) {
		model.put("user", user);

		try {
			String message = freemarkerHelper.process(newAnswerTemplate, user.getLocale(), encoding, model);

			mailHelper.sendHTML(user.getEmail(), user.getFullname(), user.getLocale(), mailSubjectKey, alternateKey, message);

			return true;
		} catch(Exception e) {
			LOG.error("Error sending mail to user: " + user, e);

			return false;
		}
	}

	/**
	 * Checks if an entity id has filled a given survey or not.
	 *
	 * @param request the request.
	 * @param response the response.
	 *
	 * @return the view name.
	 */
	public String checkEntity(final HttpServletRequest request, final HttpServletResponse response) {
		String id = request.getParameter("id");
		String entityId = request.getParameter("entity");

		int surveyId = Integer.parseInt(id);

		boolean hasEntity = false;

		try {
			hasEntity = surveyAnswerHeaderDAO.hasEntity(surveyId, entityId);
		} catch(org.hibernate.NonUniqueResultException NUREx) {
			hasEntity = true;
		}

		request.setAttribute("result", hasEntity);

		return "check-entity";
	}


	/**
	 * Performs survey and organization listing for the general public.
	 *
	 * @param request the request.
	 * @param response the response.
	 * @return the view name or null.
	 */
	public String listSurveys(final HttpServletRequest request, final HttpServletResponse response) {

		final String pathInfo = request.getPathInfo();

		if (pathInfo != null && pathInfo.length() > 0) {
			final String[] parts  = pathInfo.substring(1).split("/");
			Organization organization = null;
			// Retrieve organization
			organization = organizationDAO.findByName(parts[0]);
			if(parts.length > 0) {
	
				Survey survey = null;
	
				if(organization != null) {
	
					// Retrieve survey
					if(parts.length > 1) {
						survey = surveyDAO.findByCode(parts[1], organization.getId());
					}
	
					// Check for survey expiration and load it
					if(survey != null) {
	
						Timestamp now = new Timestamp(System.currentTimeMillis());
	
						if((survey.getLifecycle().getId() > SurveyLifecycle.PRODUCTION.getId()) || now.after(survey.getEndDate())) {
							return "survey-closed";
						}
	
						List<Map<String, Object>> result = surveyDAO.fetchQuestionTree(survey.getId());
	
						request.setAttribute("organization", organization);
						request.setAttribute("survey", survey);
						request.setAttribute("questions", result);
	
						return "survey";
					
					} else { // List organization's active surveys
	
						List<Survey> surveys = surveyDAO.findActiveSurveys(organization.getId());
	
						request.setAttribute("organization", organization);
						request.setAttribute("surveys", surveys);
	
						return "surveys";
					}
				}
			}
		}
		
		// Default view is the organization listing
		List<Organization> organizations = organizationDAO.findAll();

		request.setAttribute("organizations", organizations);

		return "organizations";
	}
}
